<?php

namespace app\common\util;

use think\db\Raw;
use think\facade\Db;

/**
 * where语句构建器
 */
class WhereBuilder implements \ArrayAccess
{
    private $where = [];

    /**
     * @return static
     */
    public static function builder()
    {
        return new static();
    }

    /**
     * 添加条件
     *
     * @param string|\think\db\Raw $column 数据库字段名
     * @param string $expr 表达式
     * @param mixed $condition 查询条件
     * @param bool $when 为false时不添加
     *
     * @return static
     */
    public function where($column, $expr = null, $condition = null, $when = true)
    {
        if ($when) {
            $this->where[] = [$column, $expr, $condition];
        }
        return $this;
    }

    /**
     * whereRaw
     *
     * @param string|Raw $raw 查询字符串
     * @param bool $when 为false时不添加
     *
     * @return static
     */
    public function whereRaw(string|Raw $raw, $when = true)
    {
        if ($when) {
            if ($raw instanceof Raw) {
                $this->where[] = $raw;
            } else {
                $this->where[] = Db::raw($raw);
            }
        }
        return $this;
    }

    /**
     * 一对一对应的构建，条件为空时不添加
     *
     * @param string $column 数据库字段名
     * @param string $expr 表达式
     * @param mixed $condition 查询条件
     *
     * @return static
     */
    public function corres($column, $expr, $condition)
    {
        if (!empty($condition)) {
            $this->where($column, $expr, $condition);
        }
        return $this;
    }

    /**
     * 简单eq
     *
     * @param mixed $column 数据库字段名
     * @param mixed $condition 表达式
     * @param bool $when 为true时一定会添加，其余时刻判断数据是否为空
     *
     * @return static
     */
    public function eq($column, $condition, $when = false)
    {
        $valid = false;
        if (is_int($condition)) {
            $valid = isset($condition);
        } elseif (is_string($condition)) {
            $valid = !empty($condition) || $condition === '0';
        } elseif (is_bool($condition)) {
            $valid = true;
        } else {
            $valid = !empty($condition);
        }
        $this->where($column, '=', $condition, $when || $valid);
        return $this;
    }

    /**
     * 简单not eq
     *
     * @param mixed $column 数据库字段名
     * @param mixed $condition 表达式
     * @param bool $when 为true时一定会添加，其余时刻判断数据是否为空
     *
     * @return static
     */
    public function neq($column, $condition, $when = false)
    {
        $valid = false;
        if (is_int($condition)) {
            $valid = isset($condition);
        } elseif (is_string($condition)) {
            $valid = !empty($condition) || $condition === '0';
        } else {
            $valid = !empty($condition);
        }
        $this->where($column, '<>', $condition, $when || $valid);
        return $this;
    }

    /**
     * %like%
     *
     * @param mixed $column 数据库字段名
     * @param mixed $condition 表达式
     * @param bool $when 为true时一定会添加，其余时刻判断数据是否为空
     *
     * @return static
     */
    public function like($column, ?string $condition = '', $when = false)
    {
        $condition = $condition ?: '';
        $this->where($column, 'like', "%{$condition}%", $when || !empty($condition));
        return $this;
    }

    public function in($column, ?array $condition = [], $exclude = [], $when = false)
    {
        $condition = $condition ?: [];
        $condition = array_diff($condition, $exclude);
        $this->where($column, 'in', $condition, $when || !empty($condition));
        return $this;
    }

    public function isnull($column, $when = false)
    {
        $this->where($column, 'null', null, $when);
        return $this;
    }

    public function notnull($column, $when = false)
    {
        $this->where($column, 'not null', null, $when);
        return $this;
    }

    /**
     * 数值范围处理
     * @param $column
     * @param $left
     * @param $right
     * @param $when
     * @return $this
     */
    public function between($column, $left, $right, $when = false)
    {
        if ($when || (self::exist($left) && self::exist($right))) {
            $this->where($column, 'between', [$left, $right]);
            return $this;
        } elseif (self::exist($left) && !self::exist($right)) {
            $this->where($column, '>=', $left);
            return $this;
        } elseif (!self::exist($left) && self::exist($right)) {
            $this->where($column, '<=', $right);
            return $this;
        } else {
            return $this;
        }
    }

    /**
     * 直接添加
     *
     * @param array $where
     *
     * @return static
     */
    public function push($where, $when = true)
    {
        if (!$when) {
            return $this;
        }
        $this->where = array_merge($this->where, $where);
        return $this;
    }

    /**
     * 构建where
     *
     * @return array
     */
    public function build()
    {
        return $this->where;
    }

    public function offsetSet($offset, $value): void
    {
        if (is_null($offset)) {
            $this->where[] = $value;
        } else {
            $this->where[$offset] = $value;
        }
    }

    public function offsetExists($offset): bool
    {
        return isset($this->where[$offset]);
    }

    public function offsetUnset($offset): void
    {
        unset($this->where[$offset]);
    }

    public function offsetGet($offset): mixed
    {
        return isset($this->where[$offset]) ? $this->where[$offset] : null;
    }

    private static function exist($condition)
    {
        $valid = false;
        if (is_int($condition)) {
            $valid = isset($condition);
        } elseif (is_string($condition)) {
            $valid = !empty($condition) || $condition === '0';
        } else {
            $valid = !empty($condition);
        }
        return $valid;
    }
}
